package com.zmm.util.document.param;

import com.zmm.util.document.IdoItem;
import com.zmm.util.document.IdoParam;
import com.zmm.util.document.ParamType;
import com.zmm.util.document.register.Param;
import com.zmm.util.document.wjl.IdoSelfItem;
import org.springframework.web.bind.annotation.PathVariable;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;

/**
 * @author 900045
 * @description:
 * @name ParamHandle
 * @date By 2021-10-27 11:09:22
 */
public final class ParamHandle {
	
	/**
	 * 需要过滤的参数类型
	 */
	private static final List<Class<?>> IGNORE_PARAM_TYPE = Arrays
			.asList(HttpServletRequest.class, HttpServletResponse.class);
	
	/**
	 * 解析 模型内的参数
	 * @author: 900045
	 * @date: 2021-10-27 11:10:21
	 * @throws 
	 * @param parent: 
	 * @param parameter: 
	 * @return: void
	 **/
	public static void parseObjectParam(IdoParam parent, Parameter parameter) {
		Field[] fields = parameter.getType().getDeclaredFields();
		IdoParam param = null;
		Param annotation = null;
		for (Field field : fields) {
			annotation = field.getDeclaredAnnotation(Param.class);
			if (annotation == null || annotation.ignore()
					|| annotation.type() == ParamType.RESPONSE) {
				continue;
			}
			param = getIdoParam(annotation, field);
			parent.addParam(param);
		}
	}

	/**
	 * 解析 嵌套的 对象 参数
	 * @author: 900045
	 * @date: 2021-10-27 11:53:11
	 * @throws 
	 * @param parent: 
	 * @param parentCls: 
	 * @return: void
	 **/
	public static void parseRespParam(IdoParam parent, Class<?> parentCls) {

		Field[] fields = parentCls.getDeclaredFields();
		Param annotation = null;
		IdoParam param = null;
		Class<?> cls = null;
		for (Field field : fields) {
			annotation = field.getDeclaredAnnotation(Param.class);
			if (annotation == null || annotation.ignore()
					|| annotation.type() == ParamType.REQUEST) {
				continue;
			}
			param = getIdoParam(annotation, field);
			parent.addParam(param);
			if (annotation.Class() != Object.class) {
				cls = annotation.Class();
			} else if (annotation.isClass()) {
				cls = param.getType();
			} else {
				continue;
			}
			//父子类型不一样才解析， 一样就跳过防止 死循环
			if (cls == parentCls) {
				continue;
			}
			param.setObject(true);
			parseRespParam(param, cls);
		}
	}

	/**
	 * 将每个方法中的参数 统一封装为 IdoParam
	 * @author: 900045
	 * @date: 2021-10-27 11:48:47
	 * @throws 
	 * @param parameter: 
	 * @return: com.zmm.util.document.IdoParam
	 **/
	public static IdoParam parseParam(Parameter parameter) {
		IdoParam param = parsePathVariable(parameter);
		if (param != null) {
			return param;
		}
		Param annotation = parameter.getDeclaredAnnotation(Param.class);
		if (annotation != null
				&& (annotation.ignore() || annotation.type() == ParamType.RESPONSE)) {
			return null;
		}
		param = new IdoParam();
		param.setName(parameter.getName());
		param.setType(parameter.getType());
		if (annotation != null) {
			param.setRequired(annotation.required());
			param.setDescription(annotation.description());
			param.setObject(annotation.isClass());
			param.setVersion(annotation.version());
			if (param.isObject()) {
				ParamHandle.parseObjectParam(param, parameter);
			}
		}
		return param;
	}


	/**
	 * 解析 带 pathVariable 参数
	 * @author: 900045
	 * @date: 2021-10-27 11:47:59
	 * @throws 
	 * @param parameter: 
	 * @return: com.zmm.util.document.IdoParam
	 **/
	public static IdoParam parsePathVariable(Parameter parameter) {
		PathVariable annotation = parameter.getDeclaredAnnotation(PathVariable.class);
		if (annotation == null) {
			return null;
		}
		IdoParam param = new IdoParam();
		param.setPathVariable(true);
		param.setName(annotation.value());
		param.setDescription(annotation.name());
		param.setRequired(true);
		param.setType(parameter.getType());
		return param;
	}

	/**
	 * 解析方法上的注解 @Param  type = 2
	 * @author: 900045
	 * @date: 2021-10-27 11:51:15
	 * @throws 
	 * @param item: 
	 * @param fields: 
	 * @return: void
	 **/
	public static void parseParamAnnotation(IdoSelfItem item, Field[] fields) {
		parseParamAnnotation(null,item,fields,2);
	}

	/**
	 * 解析 controller 上的注解 @Param  type = 1
	 * @author: 900045
	 * @date: 2021-10-27 11:51:57
	 * @throws 
	 * @param item: 
	 * @param fields: 
	 * @return: void
	 **/
	public static void parseParamAnnotation(IdoItem item, Field[] fields) {
		parseParamAnnotation(item,null,fields,1);
	}

	/**
	 * 具体实现解析
	 * @author: 900045
	 * @date: 2021-10-27 11:52:13
	 * @throws 
	 * @param item: 
	 * @param selfItem: 
	 * @param fields: 
	 * @param type: 
	 * @return: void
	 **/
	public static void parseParamAnnotation(IdoItem item, IdoSelfItem selfItem,Field[] fields, Integer type) {
		IdoParam param = null;
		Param annotation = null;
		for (Field field : fields) {
			annotation = field.getDeclaredAnnotation(Param.class);
			if (annotation == null || annotation.ignore()
					|| annotation.type() == ParamType.REQUEST) {
				continue;
			}
			param = getIdoParam(annotation, field);
			if (type == 1) {
				item.addRespParam(param);
			} else if (type == 2) {
				selfItem.addRespParam(param);
			}
			
			// 下一层
			if (annotation.Class() != Object.class) {
				ParamHandle.parseRespParam(param, annotation.Class());
				param.setObject(true);
			} else if (annotation.isClass()) {
				ParamHandle.parseRespParam(param, param.getType());
				param.setObject(true);
			}
		}
	}

	/**
	 * 请求参数解析 - 运用在普通方法上的 type = 2
	 * @author: 900045
	 * @date: 2021-10-27 09:37:06
	 * @throws
	 * @param item: 
	 * @param parameters: 
	 * @return: void
	 **/
	public static void parseReqParams(IdoSelfItem item, Parameter[] parameters) {
		parseReqParams(item, null,parameters, 2);
	}


	/**
	 * 请求参数解析 - 运用在controller上的 type = 1
	 * @author: 900045
	 * @date: 2021-10-27 11:46:58
	 * @throws 
	 * @param item: 
	 * @param parameters: 
	 * @return: void
	 **/
	public static void parseReqParams(IdoItem item, Parameter[] parameters) {
		parseReqParams(null,  item, parameters, 1);
	}

	/**
	 * 分条件执行
	 * @author: 900045
	 * @date: 2021-10-27 11:47:13
	 * @throws 
	 * @param selfItem: 
	 * @param item: 
	 * @param parameters: 
	 * @param type: 
	 * @return: void
	 **/
	private static void parseReqParams(IdoSelfItem selfItem, IdoItem item,Parameter[] parameters, Integer type) {
		IdoParam param = null;
		for (Parameter parameter : parameters) {
			if (IGNORE_PARAM_TYPE.contains(parameter.getType())) {
				continue;
			}
			param = ParamHandle.parseParam(parameter);
			if (param != null) {
				if (type == 1) {
					item.addReqParam(param);
				} else if (type ==2) {
					selfItem.addReqParam(param);
				}
				
			}
		}
	}

	/**
	 * 包装 请求参数(IdoParam)
	 * @author: 900045
	 * @date: 2021-10-27 11:47:28
	 * @throws 
	 * @param annotation: 
	 * @param field: 
	 * @return: com.zmm.util.document.IdoParam
	 **/
	private static IdoParam getIdoParam(Param annotation, Field field) {
		IdoParam param;
		param = new IdoParam();
		param.setName(field.getName());
		param.setType(field.getType());
		param.setRequired(annotation.required());
		param.setDescription(annotation.description());
		param.setVersion(annotation.version());
		return param;
	}
}
